﻿namespace My.Hydrator.Helpers
{
    using System;
    using System.Collections.Generic;
    using System.Linq;

    public static class TypeExtensions
    {
        public static bool IsEnumerable(this Type type)
        {
            return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IEnumerable<>) || type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IEnumerable<>)));
        }

        public static bool IsList(this Type type)
        {
            return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IList<>) || type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<>)));
        }

        public static bool IsDictionary(this Type type)
        {
            return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IDictionary<,>) || type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<,>)));
        }

        public static bool IsList<TType>(this Type type)
        {
            return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IList<TType>) || type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IList<TType>)));
        }

        public static bool IsDictionary<TKey, TValue>(this Type type)
        {
            return type.IsGenericType && (type.GetGenericTypeDefinition() == typeof(IDictionary<TKey, TValue>) || type.GetInterfaces().Any(x => x.IsGenericType && x.GetGenericTypeDefinition() == typeof(IDictionary<TKey, TValue>)));
        }

        public static bool IsNullable<TType>(this Type type)
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                var genericArguments = type.GetGenericArguments();
                var nullableType = genericArguments.FirstOrDefault();
                if (nullableType != null)
                {
                    return typeof(TType) == nullableType;
                }
            }

            return false;
        }

        public static bool IsNullable(this Type type, Type typeToMatch)
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>))
            {
                var genericArguments = type.GetGenericArguments();
                var nullableType = genericArguments.FirstOrDefault();
                if (nullableType != null)
                {
                    return typeToMatch == nullableType;
                }
            }

            return false;
        }

        public static bool IsNullable(this Type type)
        {
            return type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Nullable<>);
        }

        public static bool HasParameterlessConstructor(this Type type)
        {
            var constructors = type.GetConstructors();
            return constructors.Any(x => x.GetParameters().Length == 0);
        }
    }
}
